package org.example;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import org.bytedeco.ffmpeg.avformat.AVInputFormat;
import org.bytedeco.ffmpeg.global.avformat;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.jnativehook.GlobalScreen;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseListener;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class GlobalKeyListenerExample implements NativeKeyListener, NativeMouseListener {
    public static ExecutorService executor = Executors.newFixedThreadPool(20);

    public static boolean enable = false;

    public static boolean[] fk;

    //87
    public static boolean w;
    //65
    public static boolean a;
    //68
    public static boolean d;
    //83
    public static boolean s;

    public static boolean moveA = false;

    private static boolean five = false;

    private static boolean deng = false;

    private static boolean zero = false;

    private static boolean n = false;

    public static volatile long pervstop = 0L;

    public static long lastmove = 0L;

    public static long lasthuachan = 0L;

    private static boolean liantiao = false;

    public static boolean dun = false;

    public static boolean lietou = false;
    public static boolean sq = false;

    public static long i = 0L;

    private static List<Integer> actionKeys = new ArrayList<>();
    public static Robot robot;

    static {
        fk = new boolean[13];
        for (int i1 = 0; i1 < fk.length; i1++) {
            fk[i1] = false;
        }
        try {
            robot = new Robot();
        } catch (AWTException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        // 移除默认的日志记录，以清楚控制台输出
        Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
        logger.setLevel(Level.OFF);

        WinDef.HWND hWnd = User32.INSTANCE.FindWindow(null, "Edge");
        if (hWnd != null) {
            User32.INSTANCE.ShowWindow(hWnd, 0);  // 0 = SW_HIDE
        }

        try {
            new Thread(() -> {
                javacv();
//                while (true) {
//                    try {
//                        Pic.screen(GlobalKeyListenerExample.robot);
//                        Thread.sleep(0,1);
////                        Thread.sleep(3999,1);
////                        Pic.screenda(GlobalKeyListenerExample.robot);
//                    }catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
            }).start();
            MouseHook mouseHook = new MouseHook();
            new Thread(mouseHook).start();
            // 注册监听器
            GlobalScreen.registerNativeHook();
        } catch (Exception e) {
            e.printStackTrace();
        }

        GlobalScreen.addNativeKeyListener(new GlobalKeyListenerExample());
        GlobalScreen.addNativeMouseListener(new GlobalKeyListenerExample());
    }

    @Override
    public void nativeKeyPressed(NativeKeyEvent e) {
        nativeKeyPressed2(e);
    }

    @Override
    public void nativeKeyReleased(NativeKeyEvent e) {
        nativeKeyReleased2(e);
    }

    protected void nativeKeyPressed2(NativeKeyEvent e) {
        String keyText = NativeKeyEvent.getKeyText(e.getKeyCode());
        if(keyText.equalsIgnoreCase("5") && five == false) {
//            try {
//                stop();
//                long kaiqiangjiange = System.currentTimeMillis() - pervstop;
//                if(kaiqiangjiange > 150
//                ) {
//                    if(w || a || s || d) {
//                        Thread.sleep(100);
//                    }
//                    robot.keyPress(KeyEvent.VK_6);
////                    Thread.sleep(110);
//                }else {
//                    robot.keyPress(KeyEvent.VK_6);
//                }
////                for (int i = 0; i < 201; i++) {
////                    robot.mouseMove(x,y+i);
////                    Thread.sleep(1);
////                }
//
////                if(i % 2 == 0) {
////                } else if (i % 2 == 1) {
////                    Thread.sleep(110);
////                }
//                i++;
////                robot.keyRelease(KeyEvent.VK_6);
//                //two shot5
////                Thread.sleep(110);
//            } catch (InterruptedException ex) {
//                throw new RuntimeException(ex);
//            }
        }else if (keyText.equalsIgnoreCase("0")){
            try {
//                robot.keyPress(KeyEvent.VK_9);
//                Thread.sleep(Utils.random(100));
//                robot.keyPress(KeyEvent.VK_6);
//                Thread.sleep(Utils.random(30));
//                robot.keyRelease(KeyEvent.VK_9);
//                robot.keyRelease(KeyEvent.VK_6);
//                Thread.sleep(Utils.random(130));
//
//                unstop();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } else if (keyText.equalsIgnoreCase("9")) {
//            stop();
        }
        setStatus(e);
    }

    protected void nativeKeyReleased2(NativeKeyEvent e) {
        String keyText = NativeKeyEvent.getKeyText(e.getKeyCode());
        relesaseStatus(e);
        if(keyText.equalsIgnoreCase("5")) {
            robot.keyRelease(KeyEvent.VK_6);
            unstop();
        } else if (keyText.equalsIgnoreCase("等号")) {
            robot.keyRelease(KeyEvent.VK_6);
            unstop();
        } else if (keyText.equalsIgnoreCase("9")) {
            unstop();
        }
    }

    @Override
    public void nativeKeyTyped(NativeKeyEvent e) {
    }

    @Override
    public void nativeMouseClicked(NativeMouseEvent e) {

    }

    @Override
    public void nativeMousePressed(NativeMouseEvent e) {
//        stop();
    }

    @Override
    public void nativeMouseReleased(NativeMouseEvent e) {
//       unstop();
    }

    public static void stop2() {
        actionKeys.add(KeyEvent.VK_DOWN);
        actionKeys.add(KeyEvent.VK_UP);
        actionKeys.add(KeyEvent.VK_RIGHT);
        actionKeys.add(KeyEvent.VK_LEFT);
        for (Integer actionKey : actionKeys) {
            robot.keyRelease(actionKey);
        }
    }


    public static void stop() {
        if (w & a) {
//            actionKeys.add(83);
            actionKeys.add(KeyEvent.VK_DOWN);
            actionKeys.add(KeyEvent.VK_RIGHT);
        } else if (w & d) {
//            actionKeys.add(83);
            actionKeys.add(KeyEvent.VK_DOWN);
            actionKeys.add(KeyEvent.VK_LEFT);
        }else if (w) {
//            actionKeys.add(83);
            actionKeys.add(KeyEvent.VK_DOWN);
        }else if (a) {
//            actionKeys.add(68);
            actionKeys.add(KeyEvent.VK_RIGHT);
        } else if (d) {
//            actionKeys.add(65);
            actionKeys.add(KeyEvent.VK_LEFT);
        } else if (s) {
//            actionKeys.add(87);
            actionKeys.add(KeyEvent.VK_UP);
        }
        for (Integer actionKey : actionKeys) {
            robot.keyPress(actionKey);
        }
    }

    public static void unstop() {
//        System.out.println("unstopn size "+actionKeys.size());
        pervstop = System.currentTimeMillis();
        for (Integer actionKey : actionKeys) {
            robot.keyRelease(actionKey);
//            System.out.println("unstopn 抬起"+actionKey);
        }
        robot.keyRelease(KeyEvent.VK_DOWN);
        robot.keyRelease(KeyEvent.VK_UP);
        robot.keyRelease(KeyEvent.VK_LEFT);
        robot.keyRelease(KeyEvent.VK_RIGHT);

//        w = false;

//        a = false;
//        d = false;
//        s = false;
        actionKeys.clear();
    }

    private synchronized static void setStatus(NativeKeyEvent e) {
        if(actionKeys.contains(e.getKeyCode())) return;
        String keyText = NativeKeyEvent.getKeyText(e.getKeyCode());

        if(keyText.equalsIgnoreCase("w")) {
            w = true;
        }
        if(keyText.equalsIgnoreCase("a")) {
            a = true;
            moveA = false;
        }
        if(keyText.equalsIgnoreCase("s")) {
            s = true;
        }
        if(keyText.equalsIgnoreCase("d")) {
            d = true;
            moveA = true;
        }
        if(keyText.equalsIgnoreCase("5")) five = true;
        if(keyText.equalsIgnoreCase("等号")) {
            deng = true;
            pervstop = System.currentTimeMillis();
            lietou = false; sq = false;
        }
        if(keyText.equalsIgnoreCase("0")) zero = true;
        if(keyText.equalsIgnoreCase("n")) n = true;
        if(keyText.equalsIgnoreCase("6")) pervstop = System.currentTimeMillis();
        if(keyText.equalsIgnoreCase("Ctrl")) dun = true;
        if(keyText.equalsIgnoreCase("1")) lietou = true;
        if(keyText.equalsIgnoreCase("2")) sq = true;
        if(keyText.equalsIgnoreCase("3")) {lietou = false; sq = false;}
        if(keyText.equalsIgnoreCase("q")) {lietou = false; sq = false;}
        if(keyText.equalsIgnoreCase("x")) {lietou = false; sq = false;}

//        if(keyText.equalsIgnoreCase("E")) lasthuachan = new Date().getTime() + 300;

//        if(keyText.equalsIgnoreCase("Q")) lasthuachan = new Date().getTime() + 300;


    }

    private synchronized static void relesaseStatus(NativeKeyEvent e) {
        String keyText = NativeKeyEvent.getKeyText(e.getKeyCode());
//        if(p && !keyText.equalsIgnoreCase("p")) return;
//        if(actionKeys.contains(e.getKeyCode())) return;
//        for (Integer actionKey : actionKeys) {
//            robot.keyRelease(actionKey);
//        }
        if(keyText.equalsIgnoreCase("w")) {
            w = false;
            robot.keyRelease(KeyEvent.VK_DOWN);
            lastmove = System.currentTimeMillis();
        }
        if(keyText.equalsIgnoreCase("a")) {
            a = false;
            robot.keyRelease(KeyEvent.VK_RIGHT);
            lastmove = System.currentTimeMillis();
        }
        if(keyText.equalsIgnoreCase("s")) {
            s = false;
            robot.keyRelease(KeyEvent.VK_UP);
            lastmove = System.currentTimeMillis();
        }
        if(keyText.equalsIgnoreCase("d")) {
            d = false;
            robot.keyRelease(KeyEvent.VK_LEFT);
            lastmove = System.currentTimeMillis();
        }
        if(keyText.equalsIgnoreCase("5")) {
            five = false;
        }
        if(keyText.equalsIgnoreCase("6")) {
            Pic.pervshot = System.currentTimeMillis();
        }
        if(keyText.equalsIgnoreCase("等号")) deng = false;
        if(keyText.equalsIgnoreCase("n")) n = false;
        if(keyText.equalsIgnoreCase("0")) zero = false;
        if(keyText.equalsIgnoreCase("Ctrl")) dun = false;

        updateStatus(keyText);
//        actionKeys.clear();
    }

    private static void updateStatus(String keyText) {
        if(keyText.equalsIgnoreCase("上下文菜单")) {
            enable = true;
        }else if(keyText.equalsIgnoreCase("减号")){
            enable = false;
        }
        if(keyText.startsWith("F") && keyText.length() > 1) {
            for (int j = 0; j < fk.length; j++) {
                fk[j] = false;
                if(j == 4) fk[j] = true;
            }
        }
        switch (keyText) {
            case "F1" :
                fk[1] = true;
                break;
            case "F2" :
                fk[2] = true;
                break;
            case "F3" :
                fk[3] = true;
                break;
            case "F4" :
                fk[4] = true;
                break;
            case "F5" :
                fk[5] = true;
                break;
            case "F6" :
                fk[6] = true;
                break;
            case "F7" :
                fk[7] = true;
                break;
            case "F8" :
                fk[8] = true;
                break;
            case "F9" :
                fk[9] = true;
                break;
            case "F10" :
                fk[10] = true;
                break;
            case "F11" :
                fk[11] = true;
                break;
            case "F12" :
                fk[12] = true;
                break;
            default:
                break;

        }
    }

    private static void javacv() {
        try {
            FFmpegFrameGrabber.tryLoad();
        } catch (FFmpegFrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }
        // 设置捕获区域（全屏）
        int x = 600, y = 400;
        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        int width = 83;
        int height = 123;
        Rectangle screenRect2 = new Rectangle(600, 400, 83, 123); // 你可以根据需要设置屏幕尺寸
//        System.setProperty("org.bytedeco.ffmpeg.path", "C:/path/to/ffmpeg/bin");

//        System.out.println("FFmpeg version: " + org.bytedeco.ffmpeg.global.avutil.av_version_info().getString());
        // 使用 gdigrab 设备创建抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("desktop");
        //gdigrab
        //实际帧率: 55.72272372673576 fps
        //平均处理每帧: 17.0 ms

        grabber.setFormat("gdigrab");
//        grabber.setFormat("dxgi");
//        grabber.setOption("hwaccel", "auto");
//        grabber.setOption("hwaccel_output_format", "d3d11");

//        grabber.setFormat("dshow");


        grabber.setImageWidth(width);
        grabber.setImageHeight(height);
        grabber.setFrameRate(240);
        grabber.setOption("offset_x", String.valueOf(x));
        grabber.setOption("offset_y", String.valueOf(y));

        // 使用硬件加速解码
//        grabber.setVideoOption("hwaccel", "cuda");  // 或 "cuda", "dxva2", "qsv" 等
//        grabber.setVideoOption("hwaccel_device", "1"); // 指定GPU设备
//        // 设置解码线程数（根据CPU核心数调整）
//        grabber.setVideoOption("threads", "8");
//        grabber.setOption("avioflags", "direct");
//        grabber.setOption("fflags", "nobuffer");
//        grabber.setImageMode(FrameGrabber.ImageMode.RAW); // 避免自动转换
//        grabber.setOption("preset", "ultrafast");
//        grabber.setOption("tune", "zerolatency");

        try {
            grabber.start();
            Frame capturedFrame;
            while ((capturedFrame = grabber.grab()) != null) {
                if(enable) {
//                    Thread.sleep(5000);
                    BufferedImage bufferedImage = JAVACV.frameToBufferedImage(capturedFrame);
                    executor.submit(new Pic(bufferedImage));
                }
            }


            //zhenlv
//            int framesToCheck = 500; // 检查的帧数
//            long startTime = System.currentTimeMillis();
//
//            CountDownLatch countDownLatch = new CountDownLatch(500);
//            ArrayList<CompletableFuture> futures = new ArrayList<>();
//
//            ExecutorService executorService = Executors.newFixedThreadPool(10);
//            for (int i = 0; i < framesToCheck; i++) {
//                executorService.submit(() -> {
//                    Frame c = null;
//                    try {
//                        c = grabber.grab();
//                        BufferedImage bufferedImage = JAVACV.frameToBufferedImage(c);
//                        CompletableFuture<? extends Future<?>> submit = CompletableFuture.supplyAsync(() -> executor.submit(new Pic(bufferedImage)));
//                        futures.add(submit);
//                        countDownLatch.countDown();
//                    } catch (FFmpegFrameGrabber.Exception e) {
//                        throw new RuntimeException(e);
//                    }
//                });

//                    BufferedImage bufferedImage = JAVACV.frameToBufferedImage(c);
//                    CompletableFuture<? extends Future<?>> submit = CompletableFuture.supplyAsync(() -> executor.submit(new Pic(bufferedImage)));
//                    futures.add(submit);
//            }
//            countDownLatch.await();
//            long endTime = System.currentTimeMillis();
//            double actualFrameRate = framesToCheck / ((endTime - startTime) / 1000.0);
//            System.out.println("实际帧率: " + actualFrameRate + " fps");
//
//            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
//
//            long processy = System.currentTimeMillis();
//            double avgptime = ((processy - startTime) / framesToCheck);
//            System.out.println("平均处理每帧: " + avgptime + " ms");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                grabber.stop();
                grabber.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}